#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <fstream>
#include <cstring>
#include <unistd.h>

#include "prot.h"
#include "creator.h"
#include "vaddr.h"

void TestCreator::addMap(int page1, unsigned pos, int page2, Flags flags) {
  test_command cmap;
  cmap.cmd = CMD_MAP;
  cmap.page = page1;
  cmap.pos = pos;
  cmap.page2 = page2;
  
  if (options[OPT_MODE] == PM_64 && masks[page2] == OFFSET_MASK_4KB)
    cmap.addr_mask = ADDR_MASK_64_4KB;
  else
    exit(111);
  
  commands.push_back(cmap);
  
  u64 fl = (options[OPT_FLAGS] | flags.flags) & ~flags.uflags;
  if (fl) {
    test_command cflags;
    cflags.cmd = CMD_FLAGS;
    cflags.page = page1;
    cflags.pos = pos;
    cflags.flags = fl;
    cflags.uflags = 0;
  
    commands.push_back(cflags);
  }
}

int TestCreator::saveResult(const char *fileName) {
  unsigned size = results.size() * sizeof(interrupt_info);
  
  int fd = open(fileName, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
  ftruncate(fd, size);
  
  interrupt_info *r = 
    (interrupt_info *) mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
 
  memcpy(r, &results.front(), size);
  
  msync(r, size, MS_SYNC);
  munmap(r, size);
  
  close(fd);
  
  return 0;
}


unsigned calcTestFileSize(test_header *h) {
  return sizeof(test_header) +
         h->n_pages    * sizeof(u32) +
         h->n_commands * sizeof(test_command);
}

void copyTest (void *dest, test_header *h, u32 *m, test_command* c) {
  u32 *mDest = (u32 *)((test_header *)dest+1);
  test_command *cDest = (test_command *)(mDest+h->n_pages);
  
  memcpy(dest, h, sizeof(test_header));
  memcpy(mDest, m, h->n_pages * sizeof(u32));
  memcpy(cDest, c, h->n_commands * sizeof(test_command));
}

///THING ABOUT: а где ваще cmd_map.addr_mask ?


int TestCreator::saveTest(const char *fileName) {
  addFlush();
  addEnd();
  
  test_header h;
  h.n_pages = masks.size();
  h.n_commands = commands.size();
  
  unsigned size = calcTestFileSize(&h);
  
  int fd = open(fileName, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
  ftruncate(fd, size);
  
  void *file = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
  if (file == MAP_FAILED) {
    //...
  }
  
  copyTest (file, &h, &masks.front(), &commands.front());
  
  msync(file, size, MS_SYNC);
  munmap(file, size);
  
  close(fd);
  
  return 0;
}

